package ua.kpi.ipsa.expert.api.client;

import java.awt.event.*;
import java.rmi.*;
import java.rmi.registry.*;
import java.rmi.server.*;

import javax.swing.*;

import ua.kpi.ipsa.expert.api.net.*;
import ua.kpi.ipsa.expert.api.server.*;

/**
 * 
 * @author doctorpro
 * 
 */
public class ClientMain extends JFrame implements ConnectionApplicationListener {

	//
	private static final int TRIAR_SLEEP_TIME = 2000;

	//
	private LoginForm loginForm;

	//
	private boolean keepTrying = true;

	//
	private ServerGateway gateway;

	//
	private UsersConsole console;

	//f
	private final Object gatewaySync = "Для синхронизации";

	//
	private ClientFrameManager frameManager;

	/**
	 * 
	 */
	private ClientMain() {
		super("API Client");

		//
		loginForm = new LoginForm(this);
		setContentPane(loginForm);

		//
		addWindowListener(new CloseHandler());

		//
		frameManager = new ClientFrameManager(this);

		//
		launchTriar();
	}

	/**
	 * 
	 */
	private void onLoggedIn() {
		setVisible(false);
		
		//
		new CodePortionBrowser(frameManager, this);
	}

	/**
	 * 
	 * @return
	 */
	private String getServerHost() {
		return "localhost";
	}

	/**
	 * 
	 */
	private void verifyServerState() {

		Registry r = null;

		if (gateway == null) {
			try {
				r = LocateRegistry.getRegistry(getServerHost(),
						ServerMain.SERVER_PORT);

				try {
					gateway = (ServerGateway) r
							.lookup(ServerMain.REMOTE_GATEWAY_NAME);
					onServerOnline();
				} catch (AccessException e) {
					e.printStackTrace();
				} catch (RemoteException e) {
					onServerOffline();
//					 e.printStackTrace();
				} catch (NotBoundException e) {
					onServerOffline();
					e.printStackTrace();
				}

			} catch (RemoteException ex) {
				onServerOffline();
				ex.printStackTrace();
				return;
			}
		} else {
			try {
				gateway.assertOnline();
			} catch (RemoteException e) {
				gateway = null;
				onServerOffline();
				// e.printStackTrace();
			}
		}
	}

	/**
	 * 
	 */
	private void onServerOffline() {
		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				loginForm.onServerOffline();
			}
		});
	}

	/**
	 * 
	 */
	private void onServerOnline() {
		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				loginForm.onServerOnline();
			}
		});
	}

	/**
	 * 
	 */
	private void launchTriar() {

		Thread triar = new Thread() {
			@Override
			public void run() {
				while (keepTrying) {	
					synchronized (gatewaySync) {
						verifyServerState();
					}
					try {
						sleep(TRIAR_SLEEP_TIME);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		};
		triar.start();
	}

	/**
	 * 
	 */
	public void disconnect() {
		try {
			console.releaseConsole();
			console = null;
		} catch (RemoteException | ConsoleException e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public void applyConnection(String login, String pass)
			throws ConsoleException {

		synchronized (gatewaySync) {
			verifyServerState();

			try {
				ServerToUserLeash leash = new ServerToUserLeashImpl();
				ServerToUserLeash leashStub = (ServerToUserLeash) UnicastRemoteObject
						.exportObject(leash, 0);

				console = gateway.createUsersConsole(login, pass, leashStub);
				frameManager.setUsersConsole(console);

				// if we are here it means all we have just logged in
				onLoggedIn();
			} catch (RemoteException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 
	 * @author strong
	 * 
	 */
	private class ServerToUserLeashImpl implements ServerToUserLeash {

		@Override
		public boolean assertOnline() throws RemoteException {
			return true;
		}

		@Override
		public void setDisconnected() throws RemoteException {
			JOptionPane.showMessageDialog(null, "VAS KIKNULLO");

			// TODO: system exit is temporary
			// do smth here later
			System.exit(0);
		}
	}

	/**
	 * 
	 * @author doctorpro
	 * 
	 */
	private class CloseHandler extends WindowAdapter {

		@Override
		public void windowClosing(WindowEvent e) {

			System.out.println("Start exiting ...");
			System.out.println("Exited");
			System.exit(0);
		}
	}

	/**
	 * 
	 * @param args
	 */
	public static void main(String[] args) {

		JFrame c = new ClientMain();
		c.setSize(640, 480);
		c.setLocation(480, 320);
		c.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		c.pack();
		c.setVisible(true);
	}
}